package com.qinglei.recoup.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qinglei.recoup.common.domain.CommonConstant;
import com.qinglei.recoup.common.domain.RadarMessage;
import com.qinglei.recoup.common.domain.RadarUserDataDTO;
import com.qinglei.recoup.common.exception.RedisConnectException;
import com.qinglei.recoup.common.service.RedisService;
import com.qinglei.recoup.common.utils.JsonUtils;
import com.qinglei.recoup.system.dao.BedHealthStateMapper;
import com.qinglei.recoup.system.dao.BedMapper;
import com.qinglei.recoup.system.dao.RadarUserDataMapper;
import com.qinglei.recoup.system.domain.*;
import com.qinglei.recoup.system.enums.EventEnum;
import com.qinglei.recoup.system.pojo.RealTimeDataVO;
import com.qinglei.recoup.system.service.BedHealthBreathDailyDataService;
import com.qinglei.recoup.system.service.BedService;
import com.qinglei.recoup.system.service.RadarBedService;
import com.qinglei.recoup.system.service.RadarUserDataService;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @author syp
 */
@Service
@Slf4j
public class RadarUserDataServiceImpl extends ServiceImpl<RadarUserDataMapper, RadarUserData> implements RadarUserDataService {
    @Resource
    private BedService bedService;

    @Resource
    private RedisService redisService;

    @Resource
    private BedHealthBreathDailyDataService bedHealthBreathDailyDataService;

    @Resource
    private BedHealthStateMapper bedHealthStateMapper;

    public static final int STATUS_NORMAL = 1;
    public static final int STATUS_OUT_BED = 2;
    public static final int STATUS_RADAR_OFFLINE = 3;
    public static final int STATUS_MONITOR_OFF = 4;

    public static final int SUB_STATUS_CLEAR = 1;
    public static final int SUB_STATUS_LIGHT = 2;
    public static final int SUB_STATUS_DEEP = 3;



    @Override
    public void saveRadarUserData(RadarMessage message) {
        RadarUserDataDTO data = (RadarUserDataDTO) message.getData();
        // S2状态为非离床 并且 S1状态为非配合时 不保存当前数据包
        if (data.getS2() != 0 && data.getS1() != 13) {
            return;
        }
        String sn = message.getSn();
        RadarUserData radarUserData = new RadarUserData();
        radarUserData.setId(UUID.randomUUID().toString().replace("-", ""));
        radarUserData.setSn(sn);
        radarUserData.setBreathBpm(data.getBreathBpm());
        radarUserData.setHeartBpm(data.getHeartBpm());
        radarUserData.setBreathPhaseData(JsonUtils.objectToJson(data.getBreathPhaseData()));
        radarUserData.setHeartPhaseData(JsonUtils.objectToJson(data.getHeartPhaseData()));
        radarUserData.setS2Status(data.getS2());
        radarUserData.setCreateTime(new Date(message.getTimestamp()));
        radarUserData.setFrameNo(data.getFrameNo());
        this.save(radarUserData);
    }

    @Override
    public RealTimeDataVO getRealTimeData(Integer bedId) {
        BedRadarBO bedRadarBO = bedService.getBedWithSn(bedId);
        if (bedRadarBO == null) {
            return null;
        }
        RealTimeDataVO realTimeDataVO = new RealTimeDataVO();
        this.setStatus(bedRadarBO, realTimeDataVO);
        if (realTimeDataVO.getStatus() != STATUS_NORMAL) {
            return realTimeDataVO;
        }
        List<RadarUserData> radarUserDataList = baseMapper.selectList(Wrappers.<RadarUserData>lambdaQuery()
                .eq(RadarUserData::getSn, bedRadarBO.getSnCode()).orderByDesc(RadarUserData::getCreateTime).last("limit 20"));
        if (CollectionUtils.isNotEmpty(radarUserDataList) && radarUserDataList.size() == 20) {
            RadarUserData lastUserData = radarUserDataList.get(0);
            Collections.reverse(radarUserDataList);
            realTimeDataVO.setFrameNo(lastUserData.getFrameNo());
            List<Integer> heartPhaseData = new ArrayList<>(200);
            List<Integer> breathPhaseData = new ArrayList<>(200);
            for (RadarUserData userData : radarUserDataList) {
                if (userData.getS2Status() == 0) {
                    return realTimeDataVO;
                }
                String breathPhaseStr = userData.getBreathPhaseData();
                List<Integer> breathDatas = JsonUtils.jsonToList(breathPhaseStr, Integer.class);
                if (breathDatas != null) {
                    breathPhaseData.addAll(breathDatas);
                }
                String heartPhaseStr = userData.getHeartPhaseData();
                List<Integer> heartDatas = JsonUtils.jsonToList(heartPhaseStr, Integer.class);
                if (heartDatas != null) {
                    heartPhaseData.addAll(heartDatas);
                }
            }
            realTimeDataVO.setBreathBpm(lastUserData.getBreathBpm());
            realTimeDataVO.setHeartBpm(lastUserData.getHeartBpm());
            realTimeDataVO.setBreathPhaseData(breathPhaseData);
            realTimeDataVO.setHeartPhaseData(heartPhaseData);
            realTimeDataVO.setIsRadarOnline(bedRadarBO.getIsRadarOnline());

        }
        return realTimeDataVO;
    }


    private void setStatus(Bed bed, RealTimeDataVO realTimeDataVO) {
        if (bed.getIsRadarOnline() == Bed.RADAR_OFFLINE) {
            realTimeDataVO.setStatus(STATUS_RADAR_OFFLINE);
        } else if (bed.getIsRadarOn() == Bed.RADAR_OFF) {
            realTimeDataVO.setStatus(STATUS_MONITOR_OFF);
        } else if (bed.getStatus() == Bed.STATUS_ALARM) {
            this.setStatusOutBed(bed, realTimeDataVO);
            realTimeDataVO.setOutBedAlarm(true);
        } else if (bed.getStatus() == Bed.STATUS_NORMAL) {
            realTimeDataVO.setOutBedAlarm(false);
            switch (bed.getSubStatus()) {
                case Bed.SUB_STATUS_OUT_BED:
                    this.setStatusOutBed(bed, realTimeDataVO);
                    break;
                case Bed.SUB_STATUS_CLEAR:
                    realTimeDataVO.setStatus(STATUS_NORMAL);
                    realTimeDataVO.setSubStatus(SUB_STATUS_CLEAR);
                    break;
                case Bed.SUB_STATUS_LIGHT_SLEEP:
                    realTimeDataVO.setStatus(STATUS_NORMAL);
                    realTimeDataVO.setSubStatus(SUB_STATUS_LIGHT);
                    break;
                case Bed.SUB_STATUS_DEEP_SLEEP:
                    realTimeDataVO.setStatus(STATUS_NORMAL);
                    realTimeDataVO.setSubStatus(SUB_STATUS_DEEP);
                    break;
                default:
                    log.warn("setStatus 不支持的子状态 bed:{}", bed);
            }
        } else {
            log.warn("setStatus 不支持的状态 bed:{}", bed);
        }
    }

    /**
     * 设置离床状态
     *
     * @param bed
     * @param realTimeDataVO
     */
    private void setStatusOutBed(Bed bed, RealTimeDataVO realTimeDataVO) {
        realTimeDataVO.setStatus(STATUS_OUT_BED);
        LocalDateTime happenTime = bed.getHappenTime();
        long duration = 0;
        if(happenTime!=null){
             duration = System.currentTimeMillis() / 1000 - happenTime.toEpochSecond(ZoneOffset.of("+8"));
        }
        realTimeDataVO.setDuration((int) duration);
    }

}
